const emptyFn = () => {};
const isObject = (o) => o !== null && typeof o === "object";
/**
 * isEmpty 判断对象是否为空
 * @param {any} v any object
 * @returns {boolean}
 */
const isEmpty = (v) => {
  if (v === null || v === undefined || v === "") return true;
  if (Array.isArray(v) && v.length == 0) return true;
  if (isObject(v) && Object.keys(v).length == 0) return true;
  return false;
};
/**
 * not 高阶函数：对参数执行结果取反
 * @param {function} fn 任何返回布尔类型的函数
 * @returns {function}
 */
const not = (fn) => (...args) => !fn(...args);
/**
 * notEmpty 与isEmpty相反
 * @param {any} v any object
 * @returns {boolean}
 */
const notEmpty = not(isEmpty);

const stringify = (obj) => {
  let items = [];
  for (let key in obj) {
    items.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
  }
  return items.join("&");
};

const events = Symbol("events");
/**
 * Observable 实现简单的观察者模式
 *
 */
class Observable {
  constructor() {
    // private property
    this[events] = {};
    // alias
    this.on = this.addListener;
    this.off = this.removeEvent;
    this.emit = this.fireEvent;
  }
  removeEvent(name, fn) {
    if (isEmpty(this[events][name])) {
      return this;
    }
    if (fn === "*") {
      delete this[events][name];
    } else {
      const listeners = this[events][name];
      for (let [i, listener] of listeners.entries()) {
        if (listener.fn == fn) {
          listeners.splice(i, 1);
          break;
        }
      }
    }
    return this;
  }
  fireEvent(name, args) {
    if (notEmpty(this[events][name])) {
      this[events][name].forEach(function (listener) {
        listener.fn.call(listener.scope, args);
      });
    }
    return this;
  }
  addListener(name, fn, scope) {
    if (!this[events][name]) {
      this[events][name] = [];
    }
    this[events][name].push({
      fn: fn,
      scope: scope || this,
    });
    return this;
  }
}
export { Observable, emptyFn, isObject, isEmpty, not, notEmpty, stringify };
